home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / CPARITH.C < prev    next >
C/C++ Source or Header  |  1993-08-13  |  18KB  |  662 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    cparith.c
  5. //   Title:    Compress Library
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //
  24. //    This module contains arithmetic encoding and decoding routines.
  25. //    Due to allowances for multi-character sequences, encoding is slow. However,
  26. //    decoding is not affected.
  27. //
  28. //    Encoding and decoding are placed in the same module to aid in optimization.
  29. //    Since the total amount of code is small, there is not much overhead.
  30. //
  31. // The decoding routine must read past the end of the buffer in order to
  32. //    decode a string. The decode buffer should always be 2 bytes larger than
  33. //    the data to be decoded!
  34. //
  35. //
  36. //    THESE ROUTINES ARE NOT RE-ENTRANT.
  37. //
  38. //    The code in this module should be written entirely in C. 
  39. //    Do not use any C++ constructs.
  40. //
  41. //    This module is portable to:
  42. //        DOS 3.X+
  43. //        MS Windows 3.X+
  44. //        OS/2 2.X+
  45. //        OS/2 2.0 PM
  46. //        SCO UNIX.
  47. //
  48. //    The following compilers are supported:
  49. //        MSC 6.0A
  50. //        MSC/C++ 7.0
  51. //        Borland C++ 3.1 for DOS
  52. //        Borland C++ 1.0 for OS/2 2.X
  53. //        SCO UNIX cc
  54. //
  55. //----------------------------------------------------------------------------
  56. #include <cp.h>
  57.  
  58.  
  59. //----------------------------------------------------------------------------
  60. //    Constants
  61. //----------------------------------------------------------------------------
  62.  
  63. //
  64. //    Maximum number of symbols which may be encoded
  65. //    An extra symbol is always included in this -- representing the terminating 
  66. //    symbol. Therefore, a maximum of MAX_SYMBOLS-1 are available to the end
  67. //    user.
  68. //
  69. #define MAX_SYMBOLS            (256)
  70.  
  71. //
  72. //    Maximum allowed frequency count 2^14 - 1
  73. //
  74. #define MAX_FREQUENCY         (16383)
  75.  
  76. //
  77. //    Code value definition
  78. //
  79. #define CODE_VALUE_BITS     (16)            // Bit in a code value
  80. typedef long CODE_VALUE;                    // Code value representation
  81.  
  82. #define TOP_VALUE   ((CODE_VALUE)(((CODE_VALUE)1<<CODE_VALUE_BITS)-1))
  83. #define FIRST_QTR      ((CODE_VALUE)(TOP_VALUE/4+1))
  84. #define HALF          ((CODE_VALUE)(2*FIRST_QTR))
  85. #define THIRD_QTR      ((CODE_VALUE)(3*FIRST_QTR))
  86.  
  87. //----------------------------------------------------------------------------
  88. //    Variables
  89. //----------------------------------------------------------------------------
  90. static PCP_ARITH parith;                    // Current model's statistics
  91. static SIZET acCumFreq[MAX_SYMBOLS+1];    // Cumulative frequencies
  92. static SIZET cSymbols;                        // Number of symbols
  93.  
  94. #define cEof        (cSymbols)                // EOF symbol
  95.  
  96. static BYTE bBuffer;                            // Bits buffered for output
  97. static SIZET cBits2Go;                        // Number of bits free in buffer
  98. static PBYTE pbBuffer;                        // Input/output buffer pointer
  99. static SIZET cBytes;                            // Bytes input or output
  100. static SIZET cMaxBytes;                        // Maximum input or output bytes 
  101. static SIZET cGarbageBytes;                // Number of bytes past end_of_file
  102. static CODE_VALUE value;                    // Currently-seen code value */
  103. static CODE_VALUE low;                        // Ends of current code region */
  104. static CODE_VALUE high;                        // Ends of the current code region */
  105. static SIZET cBits2Follow;                    // Number of opposite bits to output after
  106.                                                     //  the next bit.
  107.  
  108. //----------------------------------------------------------------------------
  109. //    Prototypes
  110. //----------------------------------------------------------------------------
  111. static int __arithsort__(const void *, const void *);
  112. static VOID FN_L ArithAdjustSymbol(PCP_ARITH _parith, SIZET i);
  113. static int FN_L ArithBitInput(void);
  114. static VOID FN_L ArithBitOutput(int);
  115. static VOID FN_L ArithBitOutputFollow(int);
  116. static SIZET FN_L ArithDecodeSymbol(void);
  117. static VOID FN_L ArithEncodeSymbol(SIZET);
  118.  
  119.  
  120. //----------------------------------------------------------------------------
  121. //   Description:    Sort routine used by qsort to sort model statistics.
  122. //                          Sorts in decreasing order of frequency
  123. //    Parameters:    see qsort()
  124. //       Returns:    see qsort()
  125. //----------------------------------------------------------------------------
  126. static int __arithsort__(const void *pv1, const void *pv2)
  127. {
  128.     PCP_ARITH parith1 = (PCP_ARITH)pv1;
  129.     PCP_ARITH parith2 = (PCP_ARITH)pv2;
  130.  
  131.     if (parith1->cFreq > parith2->cFreq)
  132.         return -1;
  133.     else if (parith1->cFreq < parith2->cFreq)
  134.         return 1;
  135.     return 0;
  136. }
  137.  
  138.  
  139. //----------------------------------------------------------------------------
  140. //   Description:    Adjust statistics of model based on input string.
  141. //                          Note that the frequency of the last element (the EOF 
  142. //                        element) is incremented for each string
  143. //    Parameters:    _parith        Model to adjust
  144. //                        psz            String to adjust model with.
  145. //       Returns:    TRUE if successful.
  146. //----------------------------------------------------------------------------
  147. VOID FN_E ArithAdjust(PCP_ARITH _parith, PSZ psz)
  148. {
  149.     SIZET i;
  150.  
  151.     for (i = 0; _parith[i].szSymbol[0]; ++i)
  152.         _parith[i].cLen = strlen(_parith[i].szSymbol);
  153.  
  154.     for (; psz[0]; psz++)                    // Adjust symbol count for each symbol
  155.         {                                            //  in the string
  156.         SIZET cLen = 0;
  157.         SIZET cSymbol;
  158.         for (i = 0; _parith[i].szSymbol[0]; ++i)
  159.             {
  160.             if (strncmp(psz, _parith[i].szSymbol, _parith[i].cLen) == 0
  161.             && _parith[i].cLen)
  162.                 {
  163.                 cSymbol = i;
  164.                 cLen = parith[i].cLen;
  165.                 }
  166.             }
  167.         NOTUSED(cLen);
  168.         Assert(cLen);
  169.         ArithAdjustSymbol(_parith, cSymbol);
  170.         }
  171.                                                     // Find last symbol
  172.     for (i = 0; _parith[i].szSymbol[0]; ++i)
  173.         ;
  174.  
  175.     ArithAdjustSymbol(_parith, i);        // Increment by one
  176.     return ;
  177. }
  178.  
  179.  
  180. //----------------------------------------------------------------------------
  181. //   Description:    Adjust statistics of a model symbol
  182. //                          The frequency is adjusted by the size of the string.
  183. //                        Frequencies of zero are allowed!!
  184. //    Parameters:    _parith        Model to adjust
  185. //                        i                Element to increment
  186. //       Returns:    TRUE if successful.
  187. //----------------------------------------------------------------------------
  188. static VOID FN_L ArithAdjustSymbol(PCP_ARITH _parith, SIZET i)
  189. {
  190.     SIZET j;
  191.  
  192.     _parith[i].cFreq += MAX(_parith[i].cLen, 1);
  193.     if (_parith[i].cFreq >= MAX_FREQUENCY)
  194.         {                                
  195.         for (j = 0; _parith[j].szSymbol[0]; ++j)
  196.             {
  197.             if (_parith[i].cFreq)
  198.                 {
  199.                _parith[i].cFreq >>= 1;
  200.                if (!_parith[i].cFreq)
  201.                    _parith[i].cFreq = 1;
  202.                 }
  203.             }
  204.         }
  205.     return ;
  206. }
  207.  
  208.  
  209. //----------------------------------------------------------------------------
  210. //   Description:    Input a bit
  211. //    Parameters:
  212. //       Returns:    Bit
  213. //----------------------------------------------------------------------------
  214. static int FN_L ArithBitInput(void)
  215. {
  216.     int iBit;
  217.  
  218.     if (cBits2Go == 0)
  219.         {
  220.         if (cBytes >= cMaxBytes)
  221.             {
  222.             bBuffer = 0x01;                    // Garbage bits!!
  223.             cGarbageBytes++;                    // No more than 2 extra bytes allowed
  224.             Assert(cGarbageBytes <= 2);
  225.             }
  226.         else
  227.             bBuffer = *pbBuffer++;
  228.  
  229.         cBytes++;
  230.         cBits2Go = 8;
  231.         }
  232.     iBit = bBuffer & 1;
  233.     bBuffer >>= 1;
  234.     cBits2Go--;
  235.     return iBit;
  236. }
  237.  
  238.  
  239. //----------------------------------------------------------------------------
  240. //   Description:    Output a bit
  241. //    Parameters:    iBit        Bit to output
  242. //       Returns:
  243. //----------------------------------------------------------------------------
  244. static VOID FN_L ArithBitOutput(int iBit)
  245. {
  246.     bBuffer >>= 1;
  247.     if (iBit)
  248.         bBuffer |= 0x80;
  249.  
  250.     cBits2Go--;
  251.     if (cBits2Go == 0)
  252.         {
  253.         *pbBuffer++ = bBuffer;
  254.         cBytes++;
  255.         cBits2Go = 8;
  256.         }
  257.     return ;
  258. }
  259.  
  260. //----------------------------------------------------------------------------
  261. //   Description:    Output final bits
  262. //    Parameters:
  263. //       Returns:    TRUE if successful.
  264. //----------------------------------------------------------------------------
  265. static VOID FN_L ArithBitOutputFollow(int iBit)
  266. {
  267.     ArithBitOutput(iBit);
  268.     for (; cBits2Follow; --cBits2Follow)
  269.         ArithBitOutput(!iBit);
  270.  
  271.     return ;
  272. }
  273.  
  274.  
  275. //----------------------------------------------------------------------------
  276. //   Description:    Decode a buffer
  277. //    Parameters:    pbDecode            Pointer to buffer to decode.
  278. //                        pcDecode            Pointer to size of buffer. Size is adjusted
  279. //                                            by the number of bytes decoded.
  280. //                        pch                Buffer to place decoded text into.
  281. //                                            Null terminator is added to buffer.
  282. //       Returns:    TRUE if successful.
  283. //----------------------------------------------------------------------------
  284. BOOL FN_E ArithDecode(PBYTE pbDecode, PSIZET pcDecode, PCHAR pch)
  285. {
  286.     SIZET i;
  287.  
  288.     Assert(pbDecode && pcDecode && pch);
  289.     Assert(*pcDecode >= 2);
  290.  
  291.     pbBuffer = pbDecode;
  292.     cBits2Go = 0;
  293.     cGarbageBytes = 0;
  294.     cBytes = 0;
  295.     cMaxBytes = *pcDecode;
  296.     value = 0;
  297.     for (i = 1; i <= CODE_VALUE_BITS; i++)
  298.         {
  299.         value <<= 1;
  300.         value += (CODE_VALUE)ArithBitInput();
  301.         }
  302.     low = 0;
  303.     high = TOP_VALUE;
  304.     for (;;)
  305.         {
  306.         SIZET cLen;                                // Decode a symbol
  307.         SIZET cSymbol = ArithDecodeSymbol();
  308.  
  309.         if (cSymbol == cEof)
  310.             {
  311.             pch[0] = '\0';                        // Add null terminator
  312.             cBytes -= 2;                        // Always 2 garbage bytes
  313.             if (cBytes <= *pcDecode)        // Adjust number of remaining bytes
  314.                 *pcDecode -= cBytes;
  315.             else
  316.                 *pcDecode = 0;
  317.          break;
  318.             }                                        // Verify decoded string fits
  319.         cLen = strlen(parith[cSymbol-1].szSymbol);
  320.                   ;                                // Copy string to buffer
  321.         strcpy(pch, parith[cSymbol-1].szSymbol);
  322.         pch += cLen;
  323.         }
  324.     return TRUE;
  325. }
  326.  
  327.  
  328. //----------------------------------------------------------------------------
  329. //   Description:    Decode a symbol
  330. //    Parameters:
  331. //       Returns:    Symbol (1..cSymbols)
  332. //----------------------------------------------------------------------------
  333. static SIZET FN_L ArithDecodeSymbol(void)
  334. {
  335.     CODE_VALUE range;                            // Size of current code region
  336.     SIZET cCum;                                    // Cumulative frequency calculated
  337.     SIZET    cSymbol;                                // Symbol decoded
  338.  
  339.     range = (CODE_VALUE)(high - low) + 1;
  340.     cCum = (SIZET)((((CODE_VALUE)(value - low) + 1) * acCumFreq[0] - 1)/range);
  341.     for (cSymbol = 1; acCumFreq[cSymbol] > cCum; cSymbol++)
  342.         ;
  343.  
  344.    high = low + (range * acCumFreq[cSymbol - 1]) / acCumFreq[0] - 1;
  345.     low += (range * acCumFreq[cSymbol]) / acCumFreq[0];
  346.  
  347.     for (;;)
  348.         {
  349.         if (high < HALF)
  350.             {
  351.             /* nothing */ ;
  352.             }
  353.         else if (low >= HALF)
  354.             {
  355.             value -= HALF;
  356.             low -= HALF;
  357.             high -= HALF;
  358.             }
  359.         else if (low >= FIRST_QTR && high < THIRD_QTR)
  360.             {
  361.             value -= FIRST_QTR;
  362.             low -= FIRST_QTR;
  363.             high -= FIRST_QTR;
  364.             }
  365.         else
  366.             break;
  367.  
  368.         low <<= 1;
  369.         high <<= 1;
  370.         high++;
  371.         value <<= 1;
  372.         value += (CODE_VALUE)ArithBitInput();
  373.         }
  374.     return cSymbol;
  375. }
  376.  
  377.  
  378. //----------------------------------------------------------------------------
  379. //   Description:    Encode a buffer
  380. //    Parameters:    pbEncode            Pointer to buffer to encode into.
  381. //                        pcEncode            Pointer to size of buffer. Size is adjusted 
  382. //                                            by the number of bytes encoded.
  383. //                        psz                Buffer to read text from.
  384. //       Returns:    TRUE if successful.
  385. //----------------------------------------------------------------------------
  386. BOOL FN_E ArithEncode(PBYTE pbEncode, PSIZET pcEncode, PSZ psz)
  387. {
  388.     Assert(pbEncode && pcEncode && psz);
  389.     Assert(pcEncode[0]);
  390.     Assert(psz[0]);
  391.  
  392.     pbBuffer = pbEncode;
  393.     bBuffer = 0;                                // Initialize
  394.     cBits2Go = 8;
  395.     cBytes = 0;
  396.     cBits2Follow = 0;                            // No bits to follow next
  397.  
  398.     low = 0;                                        // Full code range
  399.     high = TOP_VALUE;
  400.  
  401.     while (psz[0])
  402.         {
  403.         SIZET i;
  404.         SIZET    cSymbol;
  405.         SIZET cLen = 0;
  406.                                                     // Find longest symbol
  407.         for (i = 0; parith[i].szSymbol[0]; ++i)
  408.             {
  409.             if (strncmp(psz, parith[i].szSymbol, parith[i].cLen) == 0
  410.             && parith[i].cLen > cLen)
  411.                 {
  412.                 cSymbol = i;
  413.                 cLen = parith[i].cLen;
  414.                 }
  415.             }                                        
  416.         Assert(cLen);                            // Verify valid symbol
  417.         Assert(parith[cSymbol].cFreq);    // Verify allowed symbol!
  418.         ArithEncodeSymbol(cSymbol+1);        // Encode symbol
  419.         if (cBytes >= *pcEncode)            // Check buffer overflow
  420.             return FALSE;
  421.                                                     // Move to next character
  422.         psz += cLen;
  423.         }
  424.     ArithEncodeSymbol(cEof);                // Encode terminator
  425.     cBits2Follow++;                            // And follow bits
  426.     if (low < FIRST_QTR)
  427.         ArithBitOutputFollow(0);
  428.     else
  429.         ArithBitOutputFollow(1);
  430.  
  431.     if (cBits2Go != 8)
  432.         {
  433.         if (cBytes >= *pcEncode)
  434.             return FALSE;
  435.  
  436.         *pbBuffer++ = (bBuffer >> cBits2Go);
  437.         cBytes++;
  438.         }
  439.     *pcEncode = cBytes;
  440.     return TRUE;
  441. }
  442.  
  443.  
  444. //----------------------------------------------------------------------------
  445. //   Description:    Encode a symbol
  446. //    Parameters:    cSymbol        Symbol to encode
  447. //       Returns:    
  448. //----------------------------------------------------------------------------
  449. static VOID FN_L ArithEncodeSymbol(SIZET cSymbol)
  450. {
  451.     CODE_VALUE range;
  452.  
  453.     range = (CODE_VALUE)(high - low) + 1;
  454.     high = low + (range * acCumFreq[cSymbol - 1]) / acCumFreq[0] - 1;
  455.     low = low + (range * acCumFreq[cSymbol]) / acCumFreq[0];
  456.     for (;;)
  457.         {
  458.         if (high < HALF)
  459.             {
  460.             ArithBitOutputFollow(0);
  461.             }
  462.         else if (low >= HALF)
  463.             {
  464.             ArithBitOutputFollow(1);
  465.             low -= HALF;
  466.             high -= HALF;
  467.             }
  468.         else if (low >= FIRST_QTR && high < THIRD_QTR)
  469.             {
  470.             cBits2Follow++;
  471.             low -= FIRST_QTR;
  472.             high -= FIRST_QTR;
  473.             }
  474.         else
  475.             break;
  476.  
  477.         low <<= 1;
  478.         high <<= 1;
  479.         high++;
  480.         }
  481.     return ;
  482. }
  483.  
  484.  
  485. //----------------------------------------------------------------------------
  486. //   Description:    
  487. //    Parameters:
  488. //       Returns:    TRUE if successful.
  489. //----------------------------------------------------------------------------
  490. BOOL FN_E ArithInitialize(PCP_ARITH _parith)
  491. {
  492.     SIZET i;
  493.     BOOL fDone;
  494.  
  495.     parith = _parith;                            // Store model
  496.  
  497.     if (!parith[cEof-1].cFreq)                // End of file must have freq
  498.         parith[cEof-1].cFreq = 1;
  499.     //
  500.     //    Count symbols
  501.     //
  502.     cSymbols = 0;
  503.     do
  504.         {
  505.         parith[cSymbols].cLen = strlen(parith[cSymbols].szSymbol);
  506.         Assert(parith[cSymbols].cLen < 4);
  507.         cSymbols++;
  508.         }
  509.     while (parith[cSymbols-1].szSymbol[0]);
  510.  
  511.     Assert(cSymbols <= MAX_SYMBOLS);        // Sort (except EOF symbol)
  512.     qsort(parith, cSymbols - 1, sizeof(CP_ARITH), __arithsort__);
  513.  
  514.     do                                                // Verify frequencies of model
  515.         {
  516.         SIZET cFreq = 0;
  517.  
  518.         fDone = TRUE;
  519.         for (i = 0; i < cEof; i++)
  520.             if (cFreq + parith[i].cFreq > (SIZET)MAX_FREQUENCY)
  521.                 {
  522.                 fDone = FALSE;
  523.                 break;
  524.                 }
  525.             else
  526.                 cFreq += parith[i].cFreq;
  527.  
  528.         if (!fDone)
  529.             {
  530.             for (i = 0; i < cEof; i++)
  531.                 {
  532.                 if (parith[i].cFreq)
  533.                     {
  534.                    parith[i].cFreq >>= 1;
  535.                    if (!parith[i].cFreq)
  536.                        parith[i].cFreq = 1;
  537.                     }
  538.                 }
  539.             }
  540.         }
  541.     while (!fDone);
  542.  
  543.     acCumFreq[cEof] = 0;                        // Create cumulative freqs
  544.     for (i = cEof; i > 0; i--)
  545.         acCumFreq[i-1] = acCumFreq[i] + parith[i-1].cFreq;
  546.  
  547.     return TRUE;
  548. }
  549.  
  550.  
  551. //----------------------------------------------------------------------------
  552. //   Description:    Run standard test suite
  553. //    Parameters:    sTest        Test to run.
  554. //                                        0        Run all default tests (except).
  555. //       Returns:    TRUE if successful.
  556. //----------------------------------------------------------------------------
  557. #if COMPILE_TEST
  558. BOOL FN ArithTest(SHORT sTest)
  559. {
  560. static CP_ARITH aarith[255] =
  561.     {
  562.     { 0, "d"     },
  563.     { 0, "e"     },
  564.     { 0, "f"     },
  565.     { 0, "g"     },
  566.     { 0, "h"     },
  567.     { 0, "i"     },
  568.     { 0, "j"     },
  569.     { 0, "k"     },
  570.     { 0, "l"     },
  571.     { 0, "m"     },
  572.     { 0, "n"     },
  573.     { 0, "o"     },
  574.     { 0, "p"     },
  575.     { 0, "q"     },
  576.     { 0, "a"     },
  577.    { 0, "aa"     },
  578.    { 0, "aaa"     },
  579.     { 0, "b"     },
  580.    { 0, "bb"     },
  581.    { 0, "bbb"     },
  582.    { 0, "c"     },
  583.     { 0, "cc"     },
  584.    { 0, "ccc"     },
  585.     { 0, "" }
  586.     };
  587. static PSZ pszTest1 = "abcaabbccaaabbbccc";
  588. static PSZ pszTest2 =
  589.     "aaaaaaaaaaa"
  590.     "bbbbbbbbbbb"
  591.     "ccccccccccc"
  592.     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  593.     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  594.     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  595.     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  596.     "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
  597.     "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
  598.     "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
  599.     "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
  600.     "aabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbccaabbcc";
  601. static CHAR szResult[1024];
  602. static BYTE abEncode[1024];
  603. static SIZET cEncode;
  604.     SIZET cInput, cOutput;
  605.     LONG lPercent;
  606.  
  607.     if (!sTest || sTest == 1)
  608.         {
  609.         ArithAdjust(aarith, pszTest1);
  610.         ArithAdjust(aarith, pszTest2);
  611.  
  612.         if (!ArithInitialize(aarith))
  613.             return FALSE;
  614.  
  615.         cEncode = sizeof(abEncode);
  616.         if (!ArithEncode(abEncode, &cEncode, pszTest1))
  617.             return FALSE;
  618.  
  619.         cOutput = cEncode;
  620.         cInput = strlen(pszTest1)+1;
  621.  
  622.         if (!ArithDecode(abEncode, &cEncode, szResult))
  623.             return FALSE;
  624.  
  625.         if (strcmp(szResult, pszTest1) != 0)
  626.             return FALSE;
  627.  
  628.         lPercent = ((LONG)cOutput * 100L) / (LONG)cInput;
  629.         Output("Input: %-5d  Output: %-5d   %3ld %%\n", cInput, cOutput, 100 - lPercent);
  630.  
  631.         cEncode = sizeof(abEncode);
  632.         if (!ArithEncode(abEncode, &cEncode, pszTest2))
  633.             return FALSE;
  634.  
  635.         cOutput = cEncode;
  636.         cInput = strlen(pszTest2)+1;
  637.  
  638.         if (!ArithDecode(abEncode, &cEncode, szResult))
  639.             return FALSE;
  640.  
  641.         if (strcmp(szResult, pszTest2) != 0)
  642.             return FALSE;
  643.  
  644.         lPercent = ((LONG)cOutput * 100L) / (LONG)cInput;
  645.         Output("Input: %-5d  Output: %-5d   %3ld %%\n", cInput, cOutput, 100 - lPercent);
  646.         }
  647.     else if (!sTest || sTest == 2)
  648.         {
  649.         // read into buffer encode decode and compare!!!
  650.         /* file test */ ;
  651.         }
  652.     else if (!sTest || sTest == 3)
  653.         {
  654.         /* load and save a model! */ ;
  655.         }
  656.     return TRUE;
  657. }
  658. #endif
  659. //----------------------------------------------------------------------------
  660. //------------------------------- End of File --------------------------------
  661. //----------------------------------------------------------------------------
  662.